package com.sshine.solon.rabbitmq.core;

import com.sshine.solon.rabbitmq.MessageConversionException;
import com.sshine.solon.rabbitmq.service.MessageConvert;
import org.noear.snack.ONode;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;

/**
 * @author sshine
 * @date 2022/7/25
 */
public class SimpleMessageConverter implements MessageConvert {

    public static final String DEFAULT_CHARSET = "UTF-8";

    private volatile String defaultCharset = DEFAULT_CHARSET;

    /**
     * Specify the default charset to use when converting to or from text-based
     * Message body content. If not specified, the charset will be "UTF-8".
     *
     * @param defaultCharset The default charset.
     */
    public void setDefaultCharset(String defaultCharset) {
        this.defaultCharset = (defaultCharset != null) ? defaultCharset : DEFAULT_CHARSET;
    }

    /**
     * Convert a Java object to a Message.
     *
     * @param object            the object to convert
     * @param messageProperties The message properties.
     * @return the Message
     * @throws MessageConversionException in case of conversion failure
     */
    @Override
    public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException {
        byte[] bytes = null;
        if (object instanceof byte[]) {
            bytes = (byte[]) object;
            messageProperties.setContentType(MessageProperties.CONTENT_TYPE_BYTES);
        }
        else if (object instanceof String) {
            try {
                bytes = ((String) object).getBytes(this.defaultCharset);
            }
            catch (UnsupportedEncodingException e) {
                throw new MessageConversionException(
                        "failed to convert to Message content", e);
            }
            messageProperties.setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN);
            messageProperties.setContentEncoding(this.defaultCharset);
        }
        else if (object instanceof Serializable) {
            try {
                bytes = ONode.serialize(object).getBytes();
            }
            catch (IllegalArgumentException e) {
                throw new MessageConversionException(
                        "failed to convert to serialized Message content", e);
            }
            messageProperties.setContentType(MessageProperties.CONTENT_TYPE_SERIALIZED_OBJECT);
        }
        if (bytes != null) {
            messageProperties.setContentLength(bytes.length);
            return new Message(bytes, messageProperties);
        }
        throw new IllegalArgumentException(getClass().getSimpleName()
                + " only supports String, byte[] and Serializable payloads, received: " + object.getClass().getName());
    }

    /**
     * Convert from a Message to a Java object.
     *
     * @param message the message to convert
     * @return the converted Java object
     * @throws MessageConversionException in case of conversion failure
     */
    @Override
    public Object fromMessage(Message message) throws MessageConversionException {
        Object content = null;
        MessageProperties properties = message.getMessageProperties();
        if (properties != null) {
            String contentType = properties.getContentType();
            if (contentType != null && contentType.startsWith("text")) {
                String encoding = properties.getContentEncoding();
                if (encoding == null) {
                    encoding = this.defaultCharset;
                }
                try {
                    content = new String(message.getBody(), encoding);
                }
                catch (UnsupportedEncodingException e) {
                    throw new MessageConversionException(
                            "failed to convert text-based Message content", e);
                }
            }
            else if (contentType != null &&
                    contentType.equals(MessageProperties.CONTENT_TYPE_SERIALIZED_OBJECT)) {
                    content = ONode.deserialize(new String(message.getBody()));
            }
        }
        if (content == null) {
            content = message.getBody();
        }
        return content;
    }
}
